package fr.smile.cordova.fileopener;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.String;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;

import android.annotation.TargetApi;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;


import android.app.ProgressDialog;

import android.content.Intent;
import android.net.Uri;

import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.content.pm.PackageManager;

import android.content.ActivityNotFoundException;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.support.v4.content.FileProvider;
import android.util.Log;

import static android.app.Activity.RESULT_OK;

@TargetApi(9)
public class FileOpener extends CordovaPlugin {
    private static final String FILE_OPENER = "FileOpener";
    public static final int CREATE_FILE = 101;
    public CallbackContext callbackContext;
    private String fileURL;
    private String token;
    private File localFile;

    @Override
    protected void pluginInitialize() {
        super.pluginInitialize();
    }

    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        this.callbackContext = callbackContext;
        if ("openFile".equals(action)) {
            this.fileURL = args.getString(0);
            this.token = args.getString(1);
            if (this.fileURL.startsWith("file://")) {
               try {
                   String filename = URLDecoder.decode(this.fileURL.substring(this.fileURL.lastIndexOf("/") + 1), "UTF-8");
                   String extension = this.fileURL.substring(this.fileURL.lastIndexOf(".") + 1);
                   // Local file uri (case of an already downloaded file)
                   Log.d(FILE_OPENER, "Opening file from local URI as it begins with file://");
                   File file = new File(this.fileURL.replaceFirst("^file:\\/\\/", ""));
                   Log.d(FILE_OPENER, "Local path: " + file.getPath());
                   this.openFile(file,filename, extension, this.callbackContext);
               } catch (Exception e) {

               }
            } else {
                try {
                    this.downloadAndOpenFile(this.fileURL, this.token, this.callbackContext);
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
            }
            return true;
        } else {
            return false;
        }
    }

    private void openFile(File localFile, String fileName,String extension, CallbackContext callbackContext) throws JSONException {

        JSONObject obj = new JSONObject();

        if (!localFile.exists()) {
            obj.put("message", "file not exist");
            callbackContext.error(obj);
            return;
        }

        // 系统自带的软件打开
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            String authority = cordova.getActivity().getPackageName() + ".fileprovider";
            uri = FileProvider.getUriForFile(cordova.getActivity(), authority, localFile);
            Log.e("uri",uri.getPath());
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        } else {
            uri = Uri.fromFile(localFile);
        }
        String mimetype = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        intent.setDataAndType(uri, mimetype);

        // 没有支持打开文档的安装软件
        if (cordova.getActivity().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).size() <= 0) {
            this.localFile = localFile;
            Intent exportIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
            exportIntent.addCategory(Intent.CATEGORY_OPENABLE);
            exportIntent.setType(mimetype);
            String filename = fileName;
            exportIntent.putExtra(Intent.EXTRA_TITLE, filename);
            cordova.startActivityForResult(this,exportIntent,CREATE_FILE);
            return;
        }

        try {
            cordova.getActivity().startActivity(Intent.createChooser(intent, null));
            obj.put("message", "successfull openning");
            callbackContext.success(obj);
        } catch (ActivityNotFoundException e) {
            obj.put("message", "Failed to open the file, no reader found");
            obj.put("ActivityNotFoundException", e.getMessage());
            callbackContext.error(obj);
        }
    }

    private void downloadAndOpenFile(final String fileUrl, final String token, final CallbackContext callbackContext) throws UnsupportedEncodingException {

        ProgressDialog progressDialog = new ProgressDialog(cordova.getActivity());
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setCancelable(false);
        progressDialog.setMax(100);
        progressDialog.show();

        cordova.getThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                //下载
                try {
                    String filename = URLDecoder.decode(fileUrl.substring(fileUrl.lastIndexOf("/") + 1), "UTF-8");
                    String extension = fileUrl.substring(fileUrl.lastIndexOf(".") + 1);
                    File tempFile = new File(cordova.getActivity().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),filename);
                    URL url = new URL(fileUrl);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setConnectTimeout(10 * 1000);
                    conn.setReadTimeout(10 * 1000);
                    conn.setRequestProperty("Connection", "Keep-Alive");
                    conn.setRequestProperty("Charset", "UTF-8");
                    conn.setRequestProperty("X-Auth-Token", token);
                    conn.connect();
                    String raw = conn.getHeaderField("Content-Disposition");
                    if (raw != null && raw.indexOf("=") > 0) {
                        filename = raw.split("=")[1];
                        filename = filename.replaceAll("\"", "");
                        filename = URLDecoder.decode(filename);
                        extension = filename.substring(filename.lastIndexOf(".") + 1);
                        tempFile = new File(cordova.getActivity().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),filename);
                    }

                    final String extension1 = extension;
                    final File tempFile1 = tempFile;
                    final String filename1 = filename;
                    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {

                        InputStream is = conn.getInputStream();

                        int max = conn.getContentLength();

                        FileOutputStream fos = new FileOutputStream(tempFile1);
                        int len = 0;
                        byte[] buffer = new byte[1024];
                        int total = 0;
                        while ((len = is.read(buffer)) != -1) {
                            fos.write(buffer, 0, len);
                            total += len;
                            float finalTotal = total;
                            new Handler(Looper.getMainLooper()).post(new Runnable() {
                                @Override
                                public void run() {
                                    float progress = (finalTotal / max) * 100;
                                    progressDialog.setProgress((int) progress);
                                }
                            });
                        }
                        fos.flush();
                        fos.close();
                        is.close();
                        new Handler(Looper.getMainLooper()).post(new Runnable() {
                            @Override
                            public void run() {
                                progressDialog.dismiss();
                                try {
                                    openFile(tempFile1, filename1, extension1, callbackContext);
                                } catch (JSONException e) {
                                    Log.d(FILE_OPENER, "downloadAndOpenFile", e);
                                }
                            }
                        });
                    } else {
                        new Handler(Looper.getMainLooper()).post(new Runnable() {
                            @Override
                            public void run() {
                                progressDialog.dismiss();
                                manageDownloadStatusFailed("download network error", callbackContext);
                            }
                        });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            progressDialog.dismiss();
                            manageDownloadStatusFailed(e.getMessage(), callbackContext);
                        }
                    });
                }
            }
        });
    }

    private void manageDownloadStatusFailed(String reason, CallbackContext callbackContext) {
        JSONObject obj = new JSONObject();
        try {
            obj.put("message", "Download failed for reason: #" + reason);
            callbackContext.error(obj);
        } catch (JSONException e) {
            Log.d(FILE_OPENER, "downloadAndOpenFile", e);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (resultCode != RESULT_OK) return;
        switch(requestCode) {
            case CREATE_FILE:
                if( intent != null ) {
                    Uri uri = intent.getData();
                    if( uri != null ) {
                        cordova.getThreadPool().execute(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    ParcelFileDescriptor pfd = null;
                                    pfd = cordova.getActivity().getContentResolver().openFileDescriptor(uri, "w");
                                    if( pfd != null ) {
                                        FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
                                        fileOutputStream.write(readFileToByteArray(FileOpener.this.localFile));
                                        fileOutputStream.close();
                                        JSONObject obj = new JSONObject();
                                        try {
                                            obj.put("message", "请在手机文件系统查看下载文件");
                                            callbackContext.error(obj);
                                        } catch (JSONException e) {
                                            Log.d(FILE_OPENER, "downloadAndOpenFile", e);
                                        }
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                }
                break;
        }
    }


    private byte[] readFileToByteArray(File file) {
        if(!file.exists()) {
            return null;
        }
        try {
            FileInputStream in = new FileInputStream(file);
            long inSize = in.getChannel().size();//判断FileInputStream中是否有内容
            if (inSize == 0) {
                return null;
            }

            byte[] buffer = new byte[in.available()];//in.available() 表示要读取的文件中的数据长度
            in.read(buffer);  //将文件中的数据读到buffer中
            return buffer;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}